package router

import (
	"context"
	"encoding/json"
	"errors"
	logger "gitee.com/zaper/private-logger"
	"gitee.com/zaper/service-center-client/global_sign"
	srvcerutil "gitee.com/zaper/service-center-client/util"
	"gitee.com/zaper/service-config/constant"
	"gitee.com/zaper/service-config/service/etcd"
	"gitee.com/zaper/service-config/service/model"
	sr "gitee.com/zaper/service-config/service/service_register"
	"gitee.com/zaper/service-config/task"
	"gitee.com/zaper/service-config/util"
	reg "gitee.com/zaper/software-framework/register"
	"gitee.com/zaper/software-framework/router"
	"github.com/gin-gonic/gin"
	clientv3 "go.etcd.io/etcd/client/v3"
	"io"
	"os"
	"strconv"
	"sync"
)

var (
	heartbeatPool = sync.Pool{
		New: func() any {
			return new(model.ServiceModel)
		},
	}
)

func InitializeRegister() {
	go func() {
		port := srvcerutil.GetListenPort()
		global_sign.PortChan <- port
		httpRouter := router.GetHttpRouter()
		httpRouter.RegisterRouteInstance(groups, routes, port)
		reg.InitializeRouter()
	}()
}

var groups = []string{"/api/v1/", "/api/v2"}

var routes = []router.Router{
	{groups[0], "config/register", constant.HttpPOST, []router.Option{register}},
	{groups[0], "config/submit", constant.HttpPOST, []router.Option{submitStatus}},
}

func register(ctx *gin.Context) {
	serviceModel := heartbeatPool.Get().(*model.ServiceModel)
	defer heartbeatPool.Put(serviceModel)
	err := parseServiceModel(ctx, serviceModel)
	if err != nil {
		logger.Errorf("parseParamToInstance err")
		util.NewRegisterResponse(10001, "", "register input param fail")
		return
	}
	cli, err := etcd.GetEtcdClient()
	if err != nil {
		util.NewHttpResponseError(1003, "etcd err")
		return
	}
	rAgent := sr.NewRegisterAgent(cli,
		sr.WithCtx(context.Background()),
		sr.WithNameSpace(os.Getenv(constant.ConfigRegisterKey)),
		sr.WithMaxRetry(3),
		sr.WithTTl(300),
	)
	key := rAgent.RegisterRouter(serviceModel)
	var leaseID clientv3.LeaseID
	switch key {
	case model.Register:
		leaseID, err = rAgent.Register(serviceModel)
	case model.KeepAlive:
		leaseID, err = rAgent.KeepAlive(serviceModel)
	case model.Error:
		logger.Errorf("get register route fail")
		leaseID, err = -1, errors.New("get register route fail")
	}
	var resp *util.HttpResponseError
	if err == nil && leaseID != -1 {
		resp = util.NewRegisterResponse(0, strconv.FormatInt(int64(leaseID), 10),
			"register success")
	} else {
		resp = util.NewHttpResponseError(1, "register fail")
	}
	util.HttpContextJSON(ctx, resp)
}

func parseServiceModel(ctx *gin.Context, service *model.ServiceModel) error {
	if ctx.Request.Body == nil {
		logger.Errorf("Request Body is nil")
		return errors.New("request Body is nil")
	}
	body, err := io.ReadAll(ctx.Request.Body)
	if err != nil {
		logger.Errorf("Failed to read request body %v", err)
		return errors.New("failed to read request body")
	}
	logger.Infof("[service-config] Config service to register, body is %s", body)
	err = json.Unmarshal(body, &service)
	if err != nil {
		logger.Errorf("Failed to unmarshal request body: %v", err)
		return errors.New("failed to unmarshal request body")
	}
	return nil
}

func submitStatus(ctx *gin.Context) {
	body, err := io.ReadAll(ctx.Request.Body)
	logger.Infof("Start to submitStatus, body is %s", body)
	if err != nil {
		return
	}
	var bodyMap = make(map[string]string)
	err = json.Unmarshal(body, &bodyMap)
	if err != nil {
		logger.Infof("Start to submitStatus,Unmarshal request body fail, err is %s", err)
		return
	}
	configName, ok := bodyMap["configName"]
	if !ok {
		return
	}
	serviceId, ok := bodyMap["serviceId"]
	if !ok {
		return
	}
	currentTask := task.GetTaskGroup().GetGroupCurrentTask(configName)
	if currentTask == nil {
		logger.Infof("Current task be clear, SubmitStatus, success")
		return
	}
	logger.Infof("Start to submitStatus, currentTaskId is %s", currentTask.TaskId)
	uuid, ok := bodyMap["uuid"]
	logger.Infof("Start to submitStatus, uuid is %s", uuid)
	if !ok {
		return
	}
	if currentTask.TaskId == uuid {
		logger.Infof("Start to clear service, service id is %s", serviceId)
		task.RemoveTaskService(serviceId, currentTask)
	}
	logger.Infof("SubmitStatus, success")
}
